package com.jmxcfc.blfsc.ssq.service.sealimg.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jmxcfc.blfsc.common.common.enums.ProcessStateEnum;
import com.jmxcfc.blfsc.common.common.request.BaseRequest;
import com.jmxcfc.blfsc.common.common.response.BaseResponse;
import com.jmxcfc.blfsc.common.exception.AfterOutboundException;
import com.jmxcfc.blfsc.common.exception.BeforeOutboundException;
import com.jmxcfc.blfsc.common.exception.OutboundException;
import com.jmxcfc.blfsc.common.exception.ValidBodyException;
import com.jmxcfc.blfsc.common.sign.SignRequest;
import com.jmxcfc.blfsc.common.sms.BaseContext;
import com.jmxcfc.blfsc.common.validation.rule.RequestFieldRule;
import com.jmxcfc.blfsc.common.validation.rule.SignRulesUtil;
import com.jmxcfc.blfsc.ssq.common.Constants;
import com.jmxcfc.blfsc.ssq.entity.UploadSealImgSub;
import com.jmxcfc.blfsc.ssq.entity.vo.UploadEntSealImgExtend;
import com.jmxcfc.blfsc.ssq.modle.response.SsqResponse;
import com.jmxcfc.blfsc.ssq.service.SignatureService;
import com.jmxcfc.blfsc.ssq.service.sealimg.IUploadSealImgRequestService;
import com.jmxcfc.blfsc.ssq.service.sealimg.IUploadSealImgSubService;
import com.jmxcfc.blfsc.ssq.util.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.net.URI;
import java.util.Base64;
import java.util.List;
import java.util.Objects;

import static java.util.Base64.getEncoder;

/**
 * 功能描述
 * 上传用户签名/印章图片服务类(企业章上传)
 * 参数取值于扩展字段UploadSignImageExtend
 * @author: pbs
 * @date: 2024年09月03日 23:59
 */
@Service
@Slf4j
public class UploadSealImgRequestServiceImpl implements IUploadSealImgRequestService {

    @Value("${com.ssq.uploadSealImgUrl}")
    private String uploadSealImgUrl;

    private SignatureService signatureService;
    private IUploadSealImgSubService uploadSealImgSubService;

    private RestTemplate restTemplate;



    @Autowired
    public void setSignatureService(SignatureService signatureService) {
        this.signatureService = signatureService;
    }


    @Autowired
    public void setUploadSealImgSubService(IUploadSealImgSubService uploadSealImgSubService) {
        this.uploadSealImgSubService = uploadSealImgSubService;
    }

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
    @Override
    public BaseResponse<UploadSealImgSub> sendRequest(BaseRequest<SignRequest<UploadEntSealImgExtend>> requestMessage) {
        BaseContext<String> baseContext = new BaseContext<>();
        //头部参数校验规则:业务号
        List<RequestFieldRule<?>> headerElementRules = baseContext.getHeaderElementRules();
        headerElementRules.add(SignRulesUtil.getRequestNoRule());
        //扩展字段校验: 企业章账号、企业章图片路径
        List<RequestFieldRule<?>> bodyExtendElementRules = baseContext.getBodyExtendElementRules();
        bodyExtendElementRules.add(SignRulesUtil.getSealAccountRule());
        bodyExtendElementRules.add(SignRulesUtil.getImagePathRule());
        return execute(requestMessage, baseContext);
    }


    /**
     * 重写扩展字段的校验:企业章账户、企业章路径规则校验
     * @param body (不能传JSONObject)
     *备注:每个实现类需要自己实现该方法,然后进行扩展字段的校验
     * @param baseHandleContext
     * @param <E>
     * @throws ValidBodyException
     */
    @Override
    public <E> void validBodyExtend(SignRequest<UploadEntSealImgExtend> body, BaseContext<E> baseHandleContext) throws ValidBodyException {
        try {
            if (Objects.nonNull(baseHandleContext)) {
                baseHandleContext.getBodyExtendElementRules().forEach(rule -> valid(rule, body.getExtend()));
            }
        } catch (RuntimeException e) {
            throw new ValidBodyException(e.getMessage());
        }
    }


    /**
     * 参数取值于扩展字段UploadSignImageExtend
     * account账号=>entAccount
     * imageData图片内容=>读取图片路径imagePath
     * @param request
     * @param response
     * @param baseContext
     * @throws BeforeOutboundException
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void beforeOutbound(BaseRequest<SignRequest<UploadEntSealImgExtend>> request, BaseResponse<UploadSealImgSub> response, BaseContext<String> baseContext) throws BeforeOutboundException {
        String requestNo = request.getHeader().getRequestNo();
        try {
            log.info("请求业务号requestNo:{},上传企业印章图片接口,前置处理:数据落库和参数组装", requestNo);

            UploadSealImgSub uploadSealImgSub = new UploadSealImgSub();
            uploadSealImgSub.setRequestNo(requestNo);


            //参数组织、queryUserApplyCertSub设置值
            String requestParamStr = buildParam(request, uploadSealImgSub);

            //由于是签名参数追加为url参数:/openapi/v2/signatureImage/user/create?developerId=aaaaaa&rtick=14840209310001&signType=rsa
            String urlPathParams = signatureService.buildUrlPathParams(uploadSealImgUrl, "", requestParamStr);
            //请求路径的url的参数
            baseContext.setExtendStr(urlPathParams);
            //设置请求
            baseContext.setRestHttpEntity(HttpUtils.creatRequestEntity(requestParamStr));
            //保存数据
            uploadSealImgSubService.save(uploadSealImgSub);
            //主键
            baseContext.setRecordId(uploadSealImgSub.getId());
            log.info("请求业务号requestNo:{},上传企业印章图片 接口,前置处理结束", requestNo);
        } catch (Exception e) {
            log.error("请求业务号requestNo:{},前置处理异常:{}", requestNo, e.getMessage(), e);
            throw new BeforeOutboundException(e.getMessage(), e);
        }
    }

    @Override
    public void outbound(BaseRequest<SignRequest<UploadEntSealImgExtend>> request,  BaseResponse<UploadSealImgSub> response, BaseContext<String> baseContext) throws OutboundException {
        try{
            //请求url的,必须要用URL,否则restTemplate会对url进行
            URI requestUrl = new URI( StringUtils.join(uploadSealImgUrl, baseContext.getExtendStr()));
            log.info("请求业务号requestNo:{},上传企业印章图片 接口,发送请求外呼,请求地址:{},请参数:{}",request.getHeader().getRequestNo(),requestUrl,baseContext.getRestHttpEntity().getBody());
            String resp = restTemplate.postForObject(requestUrl, baseContext.getRestHttpEntity(), String.class);
            log.info("请求业务号requestNo:{},上传企业印章图片 接口,发送请求外呼,响应内容:{}", request.getHeader().getRequestNo(), resp);
            baseContext.setRestResponse(resp);
        } catch (Exception e) {
            log.error("请求业务号requestNo:{}上传企业印章图片 接口,发送请求外呼异常:{}", request.getHeader().getRequestNo(), e.getMessage());
            throw new OutboundException(e.getMessage(), e);
        }
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void afterOutbound(BaseRequest<SignRequest<UploadEntSealImgExtend>> request,  BaseResponse<UploadSealImgSub> response, BaseContext<String> baseContext) throws AfterOutboundException {
        String requestNo = request.getHeader().getRequestNo();
        try{
            log.info("请求业务号requestNo:{},上传企业印章图片 接口,后置处理:解析响应结果", requestNo);
            UploadSealImgSub uploadSealImgSub = new UploadSealImgSub();
            uploadSealImgSub.setRequestNo(requestNo);
            //注意这边是根据主键更新
            uploadSealImgSub.setId(baseContext.getRecordId());
            SsqResponse ssqResponse = JSON.parseObject(baseContext.getRestResponse(),SsqResponse.class);
            //错误码值,0:成功
            String errno = ssqResponse.getErrno();
            //错误信息描述
            String errmsg = ssqResponse.getErrmsg();
            log.info("请求业务号requestNo:{},上传企业印章图片 接口,响应的结果 errno:{},errmsg:{}", requestNo, errno, errmsg);

            if (StringUtils.equals(errno, Constants.ERRNO_0)) {
                response.getHeader().setProcessState(ProcessStateEnum.SUCCESS);
            }else {
                response.getHeader().setProcessState(ProcessStateEnum.FAILURE);
            }
            uploadSealImgSub.setErrno(errno);
            uploadSealImgSub.setErrmsg(errmsg);
            uploadSealImgSubService.updateById(uploadSealImgSub);

            response.getHeader().setResCode(errno);
            response.getHeader().setResMessage(errmsg);
            response.setBody(uploadSealImgSub);
            log.info("请求业务号requestNo:{},上传企业印章图片 接口,后置处理结束", requestNo);
        } catch (Exception e) {
            log.error("请求业务号requestNo:{},上传企业印章图片 接口,后置处理异常:{}", requestNo, e.getMessage(), e);
            throw new AfterOutboundException(e.getMessage(), e);
        }

    }


    /**
     * 参数组装
     * @param request
     * @param uploadSealImgSub
     * @return
     * @throws Exception
     */
    private String buildParam(BaseRequest<SignRequest<UploadEntSealImgExtend>> request, UploadSealImgSub uploadSealImgSub) throws Exception {
        String requestNo = request.getHeader().getRequestNo();
        JSONObject requestParam = new JSONObject();
        //企业章账号
        requestParam.put(Constants.ACCOUNT, request.getBody().getExtend().getSealAccount());
        //图片:读取图片并转换为Base64字符串
        requestParam.put(Constants.IMAGE_DATA,imageToBase64Str(request.getBody().getExtend().getImagePath()));
        uploadSealImgSub.setAccount(requestParam.getString(Constants.ACCOUNT));
        uploadSealImgSub.setImagePath(request.getBody().getExtend().getImagePath());
        log.info("请求业务号requestNo:{}上传企业印章图片 接口,参数组织完成,参数:{}", requestNo, JSON.toJSONString(requestParam));
        return JSON.toJSONString(requestParam);
    }


    /**
     * 读取图片并转换为Base64字符串
     * @param imgFilePath
     * @return
     * @throws Exception
     */
    private String imageToBase64Str(String imgFilePath) throws Exception {

      /*  String base64Image =""
        try {
            byte[] imgData = Files.readAllBytes(file.toPath());
            base64Image = Base64.getEncoder().encodeToString(fileContent);
        } catch (IOException e) {
            log.error("读取图片路径:{},转换base64字符串异常:{}",imgFilePath,e.getMessage(),e);

        }*/

        String base64Image = "";
        byte[] data;
        try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(imgFilePath))) {
            data = new byte[inputStream.available()];
            inputStream.read(data);
            Base64.Encoder encoder = getEncoder();
            base64Image = encoder.encodeToString(data);
        } catch (Exception e) {
            log.error("读取图片路径:{},转换base64字符串异常:{}", imgFilePath, e.getMessage(), e);
            throw e;
        }
        // 加密
        return base64Image;

    }


}